Кэширование фрагментов
======================

Кэширование фрагментов относится к кэшированию фрагментов страницы. Например,
если страница отображает в таблице суммарные годовые продажи, мы можем
сохранить эту таблицу в кэше с целью экономии времени, требуемого для
генерации таблицы при каждом запросе.

Для использования кэширования фрагментов мы вызываем методы
[CController::beginCache()|CBaseController::beginCache()] и
[CController::endCache()|CBaseController::endCache()] в скрипте
представления контроллера. Эти два метода являются метками начала и конца
содержимого страницы, которое должно быть кэшировано. Как и при [кэшировании
данных](/doc/guide/caching.data), нам нужен идентификатор для определения
кэшируемого фрагмента.

~~~
[php]
…другое HTML-содержимое…
<?php if($this->beginCache($id)) { ?>
…кэшируемое содержимое…
<?php $this->endCache(); } ?>
…другое HTML-содержимое…
~~~

В приведённом коде, если метод [beginCache()|CBaseController::beginCache()] возвращает
false, то кэшированное содержимое будет автоматически вставлено в данное место;
в противном случае содержимое внутри выражения `if` будет выполнено и сохранено
в кэше, когда будет вызван метод [endCache()|CBaseController::endCache()].

Параметры кэширования
---------------

Вызывая метод [beginCache()|CBaseController::beginCache()], мы можем передать
в качестве второго аргумента массив, содержащий параметры кэширования для
управления кэшированием фрагмента. Фактически, методы
[beginCache()|CBaseController::beginCache()] и
[endCache()|CBaseController::endCache()] являются удобной обёрткой
виджета [COutputCache]. Поэтому параметры кэширования могут быть
начальными значениями любых свойств виджета [COutputCache].

### Длительность (срок хранения)

Наверное, наиболее часто используемым параметром является
[duration|COutputCache::duration],
который определяет, насколько долго содержимое кэша будет оставаться
действительным (валидным). Это похоже на параметр срока действия метода
[CCache::set()]. Следующий код помещает фрагмент в кэш не более, чем на час:

~~~
[php]
…другое HTML-содержимое…
<?php if($this->beginCache($id, array('duration'=>3600))) { ?>
…кэшируемое содержимое…
<?php $this->endCache(); } ?>
…другое HTML-содержимое…
~~~

Если мы не установим длительность (срок хранения), она будет равна
значению по умолчанию (60 секунд). Это значит, что кэшированное
содержимое станет недействительным через 60 секунд.


Начиная с версии 1.1.8, если выставить duration в 0, то соответствующее
значение будет удалено из кэша. Если же применить отрицательное значение duration,
кэш будет отключён, но существующее значение в нём останется.
До 1.1.8, как при выставлении 0, так и при использовании отрицательного
значения кэш отключался без очистки значения.

### Зависимости

Как и в случае [кэширования данных](/doc/guide/caching.data), кэшируемое содержимое
фрагмента тоже может иметь зависимости. Например, отображение
содержимого сообщения зависит от того, изменено или нет это сообщение.

Для определения зависимости мы устанавливаем параметр
[dependency|COutputCache::dependency], который может быть либо объектом,
реализующим интерфейс [ICacheDependency], либо массивом настроек, который может
быть использован для генерации объекта зависимости. Следующий код
определяет содержимое фрагмента, зависящее от изменения значения
столбца `lastModified`:

~~~
[php]
…другое HTML-содержимое…
<?php if($this->beginCache($id, array('dependency'=>array(
		'class'=>'system.caching.dependencies.CDbCacheDependency',
		'sql'=>'SELECT MAX(lastModified) FROM Post')))) { ?>
…кэшируемое содержимое…
<?php $this->endCache(); } ?>
…другое HTML-содержимое…
~~~

### Вариации (изменения)

Кэшируемое содержимое может быть изменено в соответствии с некоторыми
параметрами. Например, личный профиль может по-разному выглядеть для разных
пользователей. Для кэширования содержимого профиля мы бы хотели, чтобы
кэшированная копия была различной в соответствии с идентификатором
пользователя. По-существу, это значит, что мы должны использовать разные
идентификаторы при вызове метода [beginCache()|CBaseController::beginCache()].

Чтобы не утруждать разработчиков варьированием идентификаторов в соответствии
с некоторыми условиями, класс [COutputCache] уже включает в
себя такую возможность. Ниже приведён список встроенных вариаций:

   - [varyByRoute|COutputCache::varyByRoute]: если установлено в значение true,
кэшированное содержимое будет изменяться в зависимости от [маршрута](/doc/guide/basics.controller#route).
Поэтому каждая комбинация запрашиваемого контроллера и действия будет иметь разное кэшированное содержимое.

   - [varyBySession|COutputCache::varyBySession]: если установлено в значение
true, кэшированное содержимое будет изменяться в соответствии с
идентификатором сессии. Поэтому каждая пользовательская сессия может видеть
различное содержимое и извлекать его из кэша.

   - [varyByParam|COutputCache::varyByParam]: установив в качестве значения
массив имён, мы можем изменять кэшированное содержимое в соответствии с
заданными GET параметрами. Например, если страница отображает содержимое
сообщения в зависимости от GET-параметра `id`, мы можем определить
[varyByParam|COutputCache::varyByParam] в виде массива `array('id')` и затем
кэшировать содержимое каждого сообщения. Без такой вариации мы могли бы
кэшировать только одно сообщение.

   - [varyByExpression|COutputCache::varyByExpression]: установив в качестве значения
   выражение PHP, мы можем изменять кэшированное содержимое в
   зависимости от результата данного выражения.

### Типы запросов

Иногда нам требуется, чтобы кэширование фрагмента было включено только для некоторых
типов запросов. Например, страницу с формой мы хотим кэшировать только тогда,
когда обращение к ней произошло впервые (посредством GET запроса). Любое последующее
отображение формы (посредством POST запроса) не должно быть кэшировано,
потому что может содержать данные, введённые пользователем.
Для этого мы задаём параметр [requestTypes|COutputCache::requestTypes]:

~~~
[php]
…другое HTML содержмое…
<?php if($this->beginCache($id, array('requestTypes'=>array('GET')))) { ?>
…кэшируемое содержимое…
<?php $this->endCache(); } ?>
…другое HTML содержмое…
~~~

Вложенное кэширование
--------------

Кэширование фрагментов может быть вложенным. Это значит, что кэшируемый
фрагмент окружён более крупным фрагментом (содержится в нём), который также
кэшируется. Например, комментарии кэшируются во внутреннем фрагменте кэша,
и они же кэшируются вместе с содержимым сообщения во внешнем фрагменте кэша.

~~~
[php]
…другое HTML содержмое…
<?php if($this->beginCache($id1)) { ?>
…внешнее кэшируемое содержимое…
	<?php if($this->beginCache($id2)) { ?>
	…внутреннее кэшируемое содержимое…
	<?php $this->endCache(); } ?>
…внешнее кэшируемое содержимое…
<?php $this->endCache(); } ?>
…другое HTML содержмое…
~~~

Параметры кэширования могут быть различными для вложенных кэшей. Например,
внутренний и внешний кэши в вышеприведённом примере могут иметь разные
сроки хранения. Даже когда данные внешнего кэша уже не являются актуальными,
внутренний кеш может содержать актуальный фрагмент. Тем не менее, обратное не верно.
Если внешний кэш актуален, данные будут отдаваться из него даже если внутренний
кэш содержит устаревшие данные. Следует проявлять осторожность при выставлении
срока хранения и задания зависимостей для вложенных кэшей. В противном случае
вы можете получить устаревшие данные.